#import "Plot3DView.h"
#import "PlotShape.h"
#import <ri/ri.h>
#import <math.h>

#define SC .05
#define SCP1 SC/1.732
#define SCP2 SC/.866
#define SCP3 SC/2.45
#define SCP4 SC/1.633-SCP3

#define SWAPP(a,b) { float f; int i; for (i=0; i<3; i++) { f=a[i]; a[i]=b[i]; b[i]=f; } }

/* used to position z axis label */
struct ZAXTAB { float x,y; int d; };

@implementation PlotShape:N3DShape
- renderSelf:(RtToken)context
{
int i,j,cm;
float x,y,z,xpm,ypm;
struct ZAXTAB zaxtab[8] = { {1.0,1.0,0},{-1.0,-1.0,1},{-1.0,1.0,1},{1.0,-1.0,0} ,{-1.0,-1.0,0},{1.0,1.0,1},{1.0,-1.0,1},{-1.0,1.0,0} };
static RtPoint square[4]= {{-1.0,-1.0,-1.01},{1.0,-1.0,-1.01},{1.0,1.0,-1.01},{-1.0,1.0,-1.01}};
static RtFloat squareST[8]= { 0.0,0.0,1.0,0.0,1.0,1.0,0.0,1.0 };
static RtPoint zsquare[4]= {{-1.0,-1.0,0},{1.0,-1.0,0},{1.0,1.0,0},{-1.0,1.0,0}};
static RtPoint sq1[4]= {{-1.0,-1.0,-1.0},{-1.0,1.0,-1.0},{-1.0,1.0,1.0},{-1.0,-1.0,1.0}};
static RtPoint sq2[4]= {{-1.0,1.0,-1.0},{-1.0,1.0,1.0},{1.0,1.0,1.0},{1.0,1.0,-1.0}};
static RtPoint sq3[4]= {{1.0,1.0,1.0},{1.0,1.0,-1.0},{1.0,-1.0,-1.0},{1.0,-1.0,1.0}};
static RtPoint sq4[4]= {{-1.0,-1.0,-1.0},{1.0,-1.0,-1.0},{1.0,-1.0,1.0},{-1.0,-1.0,1.0}};
RtPoint scaX[4] = {{-1.0,-1.0,-1.0},{1.0,-1.0,-1.0},{1.0,-1.0,-1.0},{-1.0,-1.0,-1.0} };
RtPoint scaY[4] = {{-1.0,-1.0,-1.0},{-1.0,1.0,-1.0},{-1.0,1.0,-1.0},{-1.0,-1.0,-1.0} };
static RtPoint scaZ[4];
RtFloat scaST[8] = { 0,1.0,1.0,1.0,1.0,0.75,0,0.75 };
static RtFloat scaSTZ[8] = { 1.0,0.5,1.0,0,0,0,0,0.5 };
static RtPoint Box[8] = {{-SC,-SC,-SC},{-SC,-SC,SC},{-SC,SC,SC},{-SC,SC,-SC}, {SC,-SC,-SC},{SC,-SC,SC},{SC,SC,SC},{SC,SC,-SC}};
static RtInt BoxP[24] = {0,1,2,3,0,1,5,4,4,5,6,7,2,3,7,6,1,5,6,2,0,3,7,4};
static RtInt BoxV[6]={4,4,4,4,4,4};
static RtPoint Pyr[4] = {{0,-SCP2,-SCP4},{-SC,SCP1,-SCP4},{SC,SCP1,-SCP4}, {0,0,SCP4}};
static RtInt PyrP[12] = {0,1,2,0,1,3,0,2,3,1,2,3};
static RtInt PyrV[4] = {3,3,3,3};
static RtColor bgCol = {1.0,1.0,1.0};
static RtColor dCol = { 1.0,1.0,1.0 };
static RtColor opac = { .2,.2,.2 };
static RtPoint bsquare[4]= {{-100.0,-100.0,-40.0},{100.0,-100.0,-40.0},{100.0,100.0,-40.0},{-100.0,100.0,-40.0}};
RtFloat *SZ;
char tmaps[100],*tmap;
char home[60];

sprintf(home,"/tmp/%s",getenv("USER"));
if (getenv("USER")==NULL) strcpy(home,"/tmp"); 
sprintf(tmaps,"%s/plot3d.tx",home);
tmap=tmaps;

RiDeclare("texname","uniform string");
RiDeclare("Cst","uniform float");
RiDeclare("Csp","uniform float");

RiSurface("constant",RI_NULL);
if (mode>=4) {
	RiTransformBegin();
	RiRotate(chi,0,0,1.0);
	RiRotate(-theta+90.0,1.0,0,0);
	RiColor(bgCol);
	RiPolygon(4,RI_P,(RtPointer)bsquare,RI_NULL);
	RiTransformEnd();
}

RiSurface("matte",RI_NULL);
RiColor(flagcol[1]);
/* FLOOR */
if (flags&2) {
	if (mode>=4 && Omode&OVER_base) {
	/*	RiTextureCoordinates(0,0,.5,0,0,.5,.5,.5);*/
		RiSurface("texmap",(RtToken)"texname",(RtPointer)&tmap,RI_NULL);
	}
	RiPolygon(4,RI_P,(RtPointer)square,RI_ST,(RtPointer)squareST,RI_NULL);
}
RiSurface("matte",RI_NULL);
RiColor(dCol);


if (chi>90.0&&chi<270.0) ypm=-1.0;
else ypm=1.0;
if (chi<180.0) xpm=-1.0;
else xpm=1.0;

/* Backs */
if (flags&4) {
	RiColor(flagcol[2]);
	if (chi>90.0&&chi<270.0) RiPolygon(4,RI_P,(RtPointer)sq4,RI_NULL); 
	else RiPolygon(4,RI_P,(RtPointer)sq2,RI_NULL);
	if (chi<180.0) RiPolygon(4,RI_P,(RtPointer)sq1,RI_NULL);
	else RiPolygon(4,RI_P,(RtPointer)sq3,RI_NULL);
	if (flags&8) {
		RiColor(flagcol[3]);
		RiTransformBegin();
		RiTranslate(xpm,0.0,0.0);
		RiRotate(90.0,1.0,0.0,0.0);
		RiTranslate(0,tickmin[2],0.0);
		for (z=tickmin[2]; z<1.0; z+=tickstp[2]) {
			RiCylinder(.007,-1.0,1.0,360.0,RI_NULL);
			RiTranslate(0,tickstp[2],0);
		}
		RiTransformEnd();
		RiTransformBegin();
		RiTranslate(0.0,ypm,0.0);
		RiRotate(90.0,0.0,1.0,0.0);
		RiTranslate(-tickmin[2],0,0);
		for (z=tickmin[2]; z<1.0; z+=tickstp[2]) {
			RiCylinder(.007,-1.0,1.0,360.0,RI_NULL);
			RiTranslate(-tickstp[2],0,0);
		}
		RiTransformEnd();
	}
}
/* Axes */
if (flags&1 && data[0].sym!=6) {
	RiColor(flagcol[0]);
	RiTransformBegin();
	RiTranslate(-1.0,-1.0,-1.0);
	RiCylinder(.015,0.0,2.0,360.0,RI_NULL);
	RiTransformEnd();
	RiTransformBegin();
	RiRotate(-90.0,0,1.0,0.0);
	RiTranslate(-1.0,-1.0,-1.0);
	RiCylinder(.015,0.0,2.0,360.0,RI_NULL);
	RiTransformEnd();
	RiTransformBegin();
	RiRotate(90.0,1.0,0.0,0.0);
	RiTranslate(-1.0,-1.0,-1.0);
	RiCylinder(.015,0.0,2.0,360.0,RI_NULL);
	RiTransformEnd();
}
else if (flags&1) {
	RiColor(flagcol[0]);
	RiTransformBegin();
	RiCylinder(.015,-1.0,1.0,360.0,RI_NULL);
	RiTransformEnd();
	RiTransformBegin();
	RiRotate(-90.0,0,1.0,0.0);
	RiCylinder(.015,-1.0,1.0,360.0,RI_NULL);
	RiTransformEnd();
	RiTransformBegin();
	RiRotate(90.0,1.0,0.0,0.0);
	RiCylinder(.015,-1.0,1.0,360.0,RI_NULL);
	RiTransformEnd();
}

/*else if (flags&1) {
	RiColor(flagcol[0]);
	RiLine(2,RI_P,axes1,RI_NULL);
	RiLine(2,RI_P,axes2,RI_NULL);
	RiLine(2,RI_P,axes3,RI_NULL);
}*/
/* Ticks */
if (flags&8) {
	RiColor(flagcol[0]);
	RiTransformBegin();
	RiRotate(-90.0,0,1.0,0.0);
	RiTranslate(-1.0,-ypm,-1.0);
	RiCylinder(.015,0.0,2.0,360.0,RI_NULL);
	RiTransformEnd();
	RiTransformBegin();
	RiRotate(90.0,1.0,0.0,0.0);
	RiTranslate(-xpm,-1.0,-1.0);
	RiCylinder(.015,0.0,2.0,360.0,RI_NULL);
	RiTransformEnd();

	RiColor(flagcol[3]);
	RiTransformBegin();
	RiTranslate(0,-ypm,-1.0);
	RiRotate(90,0,1.0,0);
	for (x=tickmin[0]; x<1.0; x+=tickstp[0]) RiDisk(x,.03,360.0,RI_NULL);
	RiTransformEnd();
	RiTransformBegin();
	RiTranslate(-xpm,0.0,-1.0);
	RiRotate(90,1.0,0,0);
	for (x=tickmin[1]; x<1.0; x+=tickstp[1]) RiDisk(x,.03,360.0,RI_NULL);
	RiTransformEnd();
	if (!(flags&4)) {
		RiTranslate(-1.0,-1.0,0.0);
		for (x=tickmin[2]; x<1.0; x+=tickstp[2]) 
			RiDisk(x,.03,360.0,RI_NULL);
		RiTranslate(1.0,1.0,0.0);
	}
}
/* Labels */
if (flags&32 && mode>=4) {
	if (ypm<0) { SWAPP(scaX[0],scaX[1]); SWAPP(scaX[2],scaX[3]); }
	if (xpm>0) { SWAPP(scaY[0],scaY[1]); SWAPP(scaY[2],scaY[3]); }
	scaX[0][1]=scaX[1][1]=scaX[2][1]=scaX[3][1]=-ypm;
	scaY[0][0]=scaY[1][0]=scaY[2][0]=scaY[3][0]=-xpm;
	scaX[0][2]-=.5/aspect;
	scaX[1][2]-=.5/aspect;
	scaY[0][2]-=.5/aspect;
	scaY[1][2]-=.5/aspect;
	i=floor(chi/45.0);
	scaZ[0][2]=scaZ[1][2]=-1.0;
	scaZ[2][2]=scaZ[3][2]=1.0;
	scaZ[0][0]=scaZ[3][0]=zaxtab[i].x;
	scaZ[1][0]=scaZ[2][0]=zaxtab[i].x;
	scaZ[0][1]=scaZ[3][1]=zaxtab[i].y;
	scaZ[1][1]=scaZ[2][1]=zaxtab[i].y;
	if (i%2==0) {
		scaZ[1][zaxtab[i].d]*=(1.0+aspect);
		scaZ[2][zaxtab[i].d]*=(1.0+aspect);
	}
	else {
		scaZ[0][zaxtab[i].d]*=(1.0+aspect);
		scaZ[3][zaxtab[i].d]*=(1.0+aspect);
	}
	sprintf(tmaps,"%s/plot3dxyz.tx",home);
	
	x=1.05/ambient; y=0.0;
	RiSurface("texmap",(RtToken)"texname",(RtPointer)&tmap,RI_KA,(RtPointer)&x,RI_KD,(RtPointer)&y,RI_NULL);
	RiPolygon(4,RI_P,(RtPointer)scaX,RI_ST,(RtPointer)scaST,RI_NULL);

	scaST[1]=scaST[3]=.75;
	scaST[5]=scaST[7]=.5;
	RiPolygon(4,RI_P,(RtPointer)scaY,RI_ST,(RtPointer)scaST,RI_NULL);

	RiPolygon(4,RI_P,(RtPointer)scaZ,RI_ST,(RtPointer)scaSTZ,RI_NULL);

	sprintf(tmaps,"%s/plot3d.tx",home);
	RiSurface("matte",RI_NULL);
}
/* Planes */
if (flags&16) {
	RiColor(flagcol[4]);
	RiOpacity(opac);
	RiTransformBegin();
	RiTranslate(0,0,tickmin[2]);
	for (z=tickmin[2]; z<1.0; z+=tickstp[2]) {
		RiPolygon(4,RI_P,(RtPointer)zsquare,RI_NULL);
		RiTranslate(0,0,tickstp[2]);
	}
	RiTransformEnd();
	RiOpacity(dCol);
}

if (data==NULL) return self;
for (i=0; i<MAXSETS; i++) {
	if (data[i].sym<0) continue;
	if ((mode&3)>=2) RiColor(data[i].mapcol[0]);
	else RiColor(data[i].mapcol[0]);

	cm=data[i].mapmode;
	switch(data[i].sym) {
	case 0:
		for (j=0; j<data[i].ndata; j++) {
			x=data[i].data[j].x;
			y=data[i].data[j].y;
			z=data[i].data[j].z;
			if (cm) RiColor(data[i].color[j]);
			RiTransformBegin();
			RiTranslate(x,y,z);
			RiPointsPolygons(6,BoxV,BoxP,RI_P,(RtPointer)Box,RI_NULL);
			RiTransformEnd();			 
  		}
		break;
	case 1:
		for (j=0; j<data[i].ndata; j++) {
			x=data[i].data[j].x;
			y=data[i].data[j].y;
			z=data[i].data[j].z;
			if (cm) RiColor(data[i].color[j]);
			RiTransformBegin();
			RiTranslate(x,y,z);
			RiPointsPolygons(4,PyrV,PyrP,RI_P,(RtPointer)Pyr,RI_NULL);
			RiTransformEnd();			 
  		}
		break;
	case 2:
		for (j=0; j<data[i].ndata; j++) {
			x=data[i].data[j].x;
			y=data[i].data[j].y;
			z=data[i].data[j].z;
			if (cm) RiColor(data[i].color[j]);
			RiTransformBegin();
			RiTranslate(x,y,z);
			RiSphere(SC,-SC,SC,360.0,RI_NULL);
			RiTransformEnd();			 
  		}
		break;
	case 3:
		for (j=0; j<data[i].ndata; j++) {
			x=data[i].data[j].x;
			y=data[i].data[j].y;
			z=data[i].data[j].z;
			if (cm) RiColor(data[i].color[j]);
			RiTransformBegin();
			RiTranslate(x,y,z);
			RiTorus(SC,SC/3.0,0,360.0,360.0,RI_NULL);
			RiTransformEnd();			 
  		}
		break;
	case 4:
		for (j=0; j<data[i].ndata; j++) {
			x=data[i].data[j].x;
			y=data[i].data[j].y;
			z=data[i].data[j].z;
			if (cm) RiColor(data[i].color[j]);
			RiTransformBegin();
			RiTranslate(x,y,z);
			RiCylinder(SC,-SC,SC,360.0,RI_NULL);
			RiTransformEnd();			 
  		}
		break;
		
	case 5:
		/* if (data[i].fileData!=NULL) break;	/* no mesh in file mode */
		if (data[i].nx*data[i].ny!=data[i].ndata) break;
		if (mode>=4 && Omode&OVER_csurf) { 
			SZ=malloc(data[i].ndata*sizeof(RtFloat));
			for (j=0; j<data[i].ndata; j++) SZ[j]=(data[i].data[j].z+1.0)/2.0;
			RiSurface("contour",(RtToken)"Cst",(RtPointer)&Cst, (RtToken)"Csp",(RtPointer)&Csp,RI_NULL);
			if (cm) 
				RiPatchMesh(RI_BILINEAR,data[i].nx,RI_NONPERIODIC,data[i].ny,
				RI_NONPERIODIC,RI_P,(RtPointer)data[i].data,
				RI_S,(RtPointer)SZ,RI_CS,(RtPointer)data[i].color,RI_NULL);
			else 
				RiPatchMesh(RI_BILINEAR,data[i].nx,RI_NONPERIODIC,data[i].ny,
				RI_NONPERIODIC,RI_P,(RtPointer)data[i].data,
				RI_S,(RtPointer)SZ,RI_NULL);
			free(SZ);
		}
		else if (mode>=4 && Omode&OVER_surf) {
			RiSurface("texmap",(RtToken)"texname",(RtPointer)&tmap,RI_NULL);
			RiPatchMesh(RI_BILINEAR,data[i].nx,RI_NONPERIODIC,data[i].ny,
				RI_NONPERIODIC,RI_P,(RtPointer)data[i].data,RI_NULL);
		}
		else if (cm)
			RiPatchMesh(RI_BILINEAR,data[i].nx,RI_NONPERIODIC, 
			data[i].ny,RI_NONPERIODIC,RI_P,(RtPointer)data[i].data,RI_CS,
			(RtPointer)data[i].color,RI_NULL);
		else RiPatchMesh(RI_BILINEAR,data[i].nx,RI_NONPERIODIC,data[i].ny,
			RI_NONPERIODIC,RI_P,(RtPointer)data[i].data,RI_NULL);
		break;
	case 6:
		if (data[i].nx*data[i].ny!=data[i].ndata) break;
		if (mode>=4 && Omode&OVER_csurf) { 
			SZ=malloc(data[i].ndata*sizeof(RtFloat));
			for (j=0; j<data[i].ndata; j++) SZ[j]=(data[i].data[j].z+1.0)/2.0;
			RiSurface("contour",(RtToken)"Cst",(RtPointer)&Cst, (RtToken)"Csp",(RtPointer)&Csp,RI_NULL);
			if (cm) 
				RiPatchMesh(RI_BILINEAR,data[i].nx,RI_NONPERIODIC,data[i].ny,
				RI_NONPERIODIC,RI_P,(RtPointer)data[i].Sdata,
				RI_S,(RtPointer)SZ,RI_CS,(RtPointer)data[i].color,RI_NULL);
			else 
				RiPatchMesh(RI_BILINEAR,data[i].nx,RI_NONPERIODIC,data[i].ny,
				RI_NONPERIODIC,RI_P,(RtPointer)data[i].Sdata,
				RI_S,(RtPointer)SZ,RI_NULL);
			free(SZ);
		}
		else if (mode>=4 && Omode&OVER_surf) {
			RiSurface("texmap",(RtToken)"texname",(RtPointer)&tmap,RI_NULL);
			RiPatchMesh(RI_BILINEAR,data[i].nx,RI_NONPERIODIC,data[i].ny,
				RI_NONPERIODIC,RI_P,(RtPointer)data[i].Sdata,RI_NULL);
		}
		else if (cm)
			RiPatchMesh(RI_BILINEAR,data[i].nx,RI_NONPERIODIC, 
			data[i].ny,RI_NONPERIODIC,RI_P,(RtPointer)data[i].Sdata,RI_CS,
			(RtPointer)data[i].color,RI_NULL);
		else RiPatchMesh(RI_BILINEAR,data[i].nx,RI_NONPERIODIC,data[i].ny,
			RI_NONPERIODIC,RI_P,(RtPointer)data[i].Sdata,RI_NULL);
		break;
	}
}
return self;
}

-setTicks:(RtPoint)Min :(RtPoint)Step
{
tickmin[0]=Min[0];
tickmin[1]=Min[1];
tickmin[2]=Min[2];
tickstp[0]=Step[0];
tickstp[1]=Step[1];
tickstp[2]=Step[2];
return self;
}

-setData:(SetPref *)Data :(int)Mode :(int)Flags
{

data=Data;
mode=Mode;
flags=Flags;
/*
mmx[0]=mmy[0]=mmz[0]=MAXFLOAT;
mmx[1]=mmy[1]=mmz[1]=-MAXFLOAT;

for (i=0; i<MAXSETS; i++) {
	for (j=0; j<data[i].ndata; j++) {
		if (data[i].data[j].x<mmx[0]) mmx[0]=data[i].data[j].x;
		if (data[i].data[j].x>mmx[1]) mmx[1]=data[i].data[j].x;
		if (data[i].data[j].y<mmy[0]) mmy[0]=data[i].data[j].y;
		if (data[i].data[j].y>mmy[1]) mmy[1]=data[i].data[j].y;
		if (data[i].data[j].z<mmz[0]) mmz[0]=data[i].data[j].z;
		if (data[i].data[j].z>mmz[1]) mmz[1]=data[i].data[j].z;
	}
}
mmx[1]=(mmx[1]-mmx[0])/2.0;
mmy[1]=(mmy[1]-mmy[0])/2.0;
mmz[1]=(mmz[1]-mmz[0])/2.0;
*/
return self;
}

-setFlagColors:(RtColor *)col
{
bcopy(col,flagcol,sizeof(RtColor)*5);
return self;
}

- setSurfaceType:(N3DSurfaceType)st andDescendants:(BOOL)flag
{
[super setSurfaceType:st andDescendants:flag];
return self;
}

-setAng:(float)alt :(float)az :(float)Aspect :(float)Ambient
{
RtPoint ax;
RtMatrix mx = { { -1.0,0,0,0 }, {0,1.0,0,0}, {0,0,1.0,0}, {0,0,0,1.0} };

theta=alt*180.0/M_PI;
chi=az*180.0/M_PI;
aspect=Aspect;
ambient=Ambient;

[self setTransformMatrix:mx];

[self scale:1.0 :1.0 :Aspect];

ax[0]=ax[1]=0; ax[2]=1.0;
[self rotateAngle:chi axis:ax];

ax[0]=1.0; ax[1]=ax[2]=0;
[self rotateAngle:theta-90.0 axis:ax];

return self;
}

- setOver:(int)OMODE
{
Omode=OMODE;
return self;
}

-setContour:(float)start :(float)space
{
Cst=start;
Csp=space;
return self;
}
@end
  
